using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Advent.aiDevices;

namespace Advent
{
    /// <summary>
    /// This class provides some Central Office specific examples 
    /// </summary>
    class COExamples
    {


        /// <summary>
        /// This demonstrates how to generate CallerID shortly after ringing
        /// </summary>
        /// <param name="_7280"></param>
        public static void SendCallerIDAfterRing(AI7280_CO_Simulator _7280)
        {

            // Specify a 60 Vrms ringing signal at 22 Hz for 1 second
            RingingBurst Ring = new RingingBurst(SignalLevel.InVrms(60),
                                                Frequency.InHz(22),
                                                DCVoltage.InVolts(48),
                                                TimeInterval.InSeconds(1));


            FSKCallerIDData Msg =  TIA.CallSetupMessage(new CallerIDDateTime(12, 15, 9, 0), // Dec 15 at 9 am
                                                        "Advent","6049444298");

            // Specify the FSK physical settings based on the ETSI standard
            FSKPhysicalSettings Phys = FSKPhysicalSettings.GetDefaults( CallerIDStandardBody.ETSI, 
                                                                    SignalLevel.IndBV(-8),      // average level
                                                                    UnitlessQuantity.IndB(-2)); // twist


            // Now we construct the Caller ID FSK transmission we are going to send after ringing 
            FSKCallerIDTransmission TX = new FSKCallerIDTransmission(Msg,   // message contents (above)
                                                                     100,   // Channel seizure bits
                                                                     140,   // Mark bits
                                                                     1,     // Stop bits
                                                                     3,     // markout bits
                                                                     Phys); // physical settings (above)

            //Schedule ringing to start in 500 ms from now
            TimeStamp RingStartTime = _7280.Time.Now() + TimeInterval.InMilliseconds(500);
            _7280.RingGenerator.Generate(Ring,RingStartTime);


            // Now schedule the CallerID to be sent 200 ms after the end of ringing
            _7280.FSKGenerator.Generate(TX, RingStartTime  + Ring.Duration + TimeInterval.InMilliseconds(200));

            // Wait until the FSK generator stops before continuing
            TimeStamp T = _7280.Wait.Until(ActionType.FSK_Generator_Finished, TimeInterval.InSeconds(5));
        }

        /// <summary>
        /// This demonstrates how to send CAS and then send CallerID
        /// </summary>
        /// <param name="_7280"></param>
        public static void Send_CAS_CallerID(AI7280_CO_Simulator _7280)
        {

            /**************************************************************
             * We construct our signal definitions in advance
             * *************************************************************/
            CAS Alert = new CAS(SignalLevel.IndBm(-5), TimeInterval.InMilliseconds(80));


            // Specify the FSK physical settings based on the ETSI standard
            FSKPhysicalSettings Phys = FSKPhysicalSettings.GetDefaults(CallerIDStandardBody.ETSI,
                                                                    SignalLevel.IndBV(-8),      // average level
                                                                    UnitlessQuantity.IndB(-2)); // twist
            // Create the content of the message 
            FSKData Msg = ETSI.CallSetupMessage(CallerIDDateTime.Now(), // use current time
                                                "John Doe",             // calling name
                                                "5551234");             // calling number

            // Now we construct the Caller ID FSK transmission we are going to send after ringing 
            FSKCallerIDTransmission TX = new FSKCallerIDTransmission(Msg,   // message contents (above)
                                                                     100,   // Channel seizure bits
                                                                     140,   // Mark bits
                                                                     1,     // Stop bits
                                                                     3,     // markout bits
                                                                     Phys); // physical settings (above)

            /**************************************************************
             * Now we schedule each signal for delivery
             * *************************************************************/

            // We pre-configure the FSK generator so we can start FSK with low latency
            _7280.FSKGenerator.Configure(TX);


            // Schedule to transmit CAS a short time in the future
            TimeStamp CASTime = _7280.Time.Now() + TimeInterval.InMilliseconds(500);

            // Schedule the CAS to be generated
            _7280.MFGenerator.Generate(Alert, CASTime);

            // We schedule to start the FSk generator
            _7280.FSKGenerator.Generate(CASTime + Alert.Duration +  TimeInterval.InMilliseconds(50));


        }

        /// <summary>
        /// This demonstrates how to generate CallerID with a bad checksum
        /// </summary>
        public static void Send_CallerID_With_Bad_Checksum(AI7280_CO_Simulator _7280)
        {


            // Specify the FSK physical settings based on the ETSI standard
            FSKPhysicalSettings Phys = FSKPhysicalSettings.GetDefaults(CallerIDStandardBody.ETSI,
                                                                    SignalLevel.IndBV(-8),      // average level
                                                                    UnitlessQuantity.IndB(-2)); // twist



            // We construct a CallerID message as usual 
            FSKData Msg = TIA.CallSetupMessage(CallerIDDateTime.Now(),
                                            TIA.ReasonForAbsence.Private_Number,   // Name is absent (private)
                                            "5551234");


            /************************************************************************
             * We construct a CallerID message exactly as usual. Once constructed we 
             * can modify the bytes within the message directly using the SetByte method.
             * Note: these changes will be overwritten if you modify any high level parameters!
             ************************************************************************/
            byte XSum = Msg.GetByte(Msg.ByteCount - 1);

            XSum = (byte) ((XSum-1) & 0xFF);        // We modify the checksum

            Msg.SetByte(Msg.ByteCount - 1, XSum);



            // Now we construct the Caller ID FSK transmission we are going to send after ringing 
            FSKCallerIDTransmission TX = new FSKCallerIDTransmission(Msg,   // message contents (above)
                                                                     0,   // Channel seizure bits
                                                                     140,   // Mark bits
                                                                     2,     // Stop bits
                                                                     3,     // markout bits
                                                                     Phys); // physical settings (above)

            // Actually send the Caller ID
            _7280.FSKGenerator.Generate(TX);


        }

        /// <summary>
        /// This example demonstrates how to generate a Caller ID message with a custom bit
        /// encoding. In this particular example it shows how to elongate particular stop bits.
        /// </summary>
        public static void Send_CallerID_With_Stopbit_Stuffing(AI7280_CO_Simulator _7280)
        {


            // We construct a CallerID message 
            FSKData Msg = TIA.CallSetupMessage(CallerIDDateTime.Now(),
                                            TIA.ReasonForAbsence.Private_Number,   // Name is absent (private)
                                            "5551234");

            // Creates a transmission with custom bit pattern encoder!
            FSKCallerIDTransmission TX = new FSKCallerIDTransmission(Msg,
                              0, 100, 1, 2,
                              FSKPhysicalSettings.GetDefaults(),
                              ElongateStopBits); // <- Custom encoder

            _7280.FSKGenerator.Generate(TX);
        }


        /// <summary>
        /// This function can be used as a delegate for the FSKCallerIDTranmission 
        /// to perform the bit encoding based on the contents of the object. In this
        /// example we elongate each 8th stop bit by 10 bits
        /// </summary>
        /// <param name="TX">CallerID Transmission to encode</param>
        static void ElongateStopBits(FSKCallerIDTransmission TX)
        {
            BitPattern P = TX.BitPattern;
            
            // Remove any previous pattern
            P.Clear();
            
            // Channel Seizure
            P.AddAlternatingBits(100, false);
            
            // Mark time
            P.AddSetBits(TX.MarkBits);

            // Encode the data contents
            for (int i = 0; i < TX.Message.ByteCount; i++)
            {
                // Start Bit
                P.AddClearedBits(1);
                // Byte Value       
                P.AddByte_LSBFirst(TX.Message.GetByte(i));
                // Stop Bit
                P.AddSetBits(1);
                //Elongate every 8th stop bit by 10 bits!
                if ((i % 8) == 0) P.AddSetBits(10);
            }

            // Mark Out
            P.AddSetBits(TX.MarkOutBits);
        }


        /// <summary>
        /// This demonsrates how to use the scheduling features to send CallerID with synchronous noise
        /// </summary>
        public static void Send_CallerID_With_Noise(AI7280_CO_Simulator _7280)
        {

            // This shows how each physical parameter can be adjusted independently
            FSKPhysicalSettings Phys = new FSKPhysicalSettings(Frequency.InHz(1204),         // Mark + 4 Hz
                                                                Frequency.InHz(2104),       // Space + 4 Hz
                                                                SignalLevel.IndBm(-6),      // -6 dBm average level
                                                                UnitlessQuantity.IndB(2),   // 2 dB twist
                                                                Frequency.InHz(1200));      // 1200 baud
            
            // Visual Message Waiting Indicator message
            FSKCallerIDData Msg = TIA.MDMF_VMWI_Message(true);

            // Create the actual FSK transmission containing all the parameters
            FSKCallerIDTransmission TX = new FSKCallerIDTransmission(Msg, 0, 100, 1, 4, Phys);


            // Schedule the FSK generator to transmit 1 second from now
            TimeStamp FSKTime = _7280.Time.Now() + TimeInterval.InSeconds(1);
            _7280.FSKGenerator.Generate(TX,FSKTime);

            // schedule the noise generator to start 100 ms before and stop 100 ms after the FSK
            _7280.NoiseGenerator.Generate(SignalLevel.IndBm(-30), FSKTime - TimeInterval.InMilliseconds(100));
            _7280.NoiseGenerator.StopGenerator( FSKTime + TX.Duration  +  TimeInterval.InMilliseconds(100));


        }


    }
}
